package api

import (
	"go-gw-scaffold/api/loadbanlance"
	"go-gw-scaffold/api/loadbanlance/inst"
	"go-gw-scaffold/dto"
	"go-gw-scaffold/middleware"
	"go-gw-scaffold/util"
	"log"

	"github.com/gin-gonic/gin"
)

type Gwscaffold struct {
	isAutoLoadbanlance bool
	conf               *dto.GwsConf
	manager            *loadbanlance.LoadbanlanceManager
}

func newInstance(conf *dto.GwsConf) *Gwscaffold {
	if conf.Host == "" {
		log.Fatal("Host is empty")
		return nil
	}
	if conf.Port == "" {
		log.Fatal("Port is empty")
		return nil
	}
	if conf.Remotes == nil {
		log.Fatal("Remotes is nil")
		return nil
	}
	if conf.HandlePrefix == "" {
		log.Fatal("HandlePrefix is empty")
		return nil
	}
	if len(conf.Remotes) == 0 {
		log.Fatal("Remotes length is zero")
		return nil
	}
	return &Gwscaffold{
		conf:    conf,
		manager: loadbanlance.NewLoadbanlanceManager(),
	}
}

func GwsInstance(confPath string) *Gwscaffold {
	if confPath == "" {
		log.Fatal("confPath is invalid")
		return nil
	}
	conf, error := util.ParseGWSConfig(confPath)
	if error != nil {
		log.Fatal("ParseGWSConfig is error")
		return nil
	}
	return newInstance(conf)
}
func (_this *Gwscaffold) SetAutoLoadbanlance(auto bool) {
	_this.isAutoLoadbanlance = auto
}
func (_this *Gwscaffold) AddLoadbanlance(name string, banlance loadbanlance.Banlancer) {
	if name == "" {
		log.Fatal("name is invalid")
		return
	}
	if banlance == nil {
		log.Fatal("banlance is nil")
		return
	}
	_this.manager.Add(name, banlance)
}
func (_this *Gwscaffold) Run(callback func(data interface{})) {
	if callback == nil {
		log.Fatal("callback is nil")
		return
	}
	serverOptions := &dto.ServerOptions{
		Host: _this.conf.Host,
		Port: _this.conf.Port,
	}
	if _this.isAutoLoadbanlance {
		if len(_this.conf.Remotes) >= 10 {
			_this.manager.Add("round_robin", inst.NewRoundRobinBanlance())
		} else {
			_this.manager.Add("random", inst.NewRandomBanlance())
		}
	}
	CreateServer(serverOptions, func(engine *gin.Engine) {
		reverseOptions := &dto.ReverseOptions{
			HandlePath:   _this.conf.HandlePrefix,
			Remotes:      _this.conf.Remotes,
			BanlanceType: _this.conf.LoadbanlanceType,
			Headers:      _this.conf.Headers,
			IpAllows:     _this.conf.IpAllows,
		}
		engine.Use(
			middleware.AuthorizeMiddleware(),
			middleware.IPAllowsMiddleware(_this.conf.IpAllows),
			middleware.RequestLimiterMiddleware(),
		)
		engine.GET(_this.conf.HandlePrefix, func(ctx *gin.Context) {
			reverseProxy := NewLoadbanlanceReverseProxy(reverseOptions, _this.manager, func(data map[string]interface{}) {
				callback(data)
			})
			reverseProxy.ServeHTTP(ctx.Writer, ctx.Request)
		})
	})
}
